/**
 * 74hc595.c - 串转并芯片功能封装
 * by Nixsawe <ziming_cool@126.com>
 * 2021-12-16 ~ 2022-1-27
 * 
 * 封装串转并芯片功能函数，以方便调用
 */

#include "74hc595.h"

unsigned char last_data;

/**
 * 将 8 位二进制数值 dat 按串行数据输出
 * 74HC595 状态缓存器中定义 QA(Q0) 脚对应的是最高位，相应的 QH(Q7) 是最低位
 */
void s2p_write_data(unsigned char dat)
{
	int i;

	last_data = dat;

	// 输出 8 位数据
	for(i = 0; i < 8; i ++)
	{
		// 先输出高位，后输出低位
		S2P_SHIFT_BIT(dat >> 7);	// 将目前最高有效位传递过去

		// 较低的位左移，次高位将作为下一次的最高位输出
		dat <<= 1;

		// 在移位寄存器时钟线上建立一个上升沿
		S2P_SREDGE();
	}

	// 在锁存寄存器时钟线上建立一个上升沿
	S2P_REDGE();

	// 字节写入完毕
	// return;
}

/**
 * 将 8 位二进制数值 dat 按串行数据输出，但不立即使用上升沿更新显示
 * 74HC595 状态缓存器中定义 QA(Q0) 脚对应的是最高位，相应的 QH(Q7) 是最低位
 */
void s2p_write_data_no_edge(unsigned char dat)
{
	int i;

	last_data = dat;

	// 输出 8 位数据
	for(i = 0; i < 8; i ++)
	{
		// 先输出高位，后输出低位
		S2P_SHIFT_BIT(dat >> 7);	// 将目前最高有效位传递过去

		// 较低的位左移，次高位将作为下一次的最高位输出
		dat <<= 1;

		// 在移位寄存器时钟线上建立一个上升沿
		S2P_SREDGE();
	}

	// 字节写入完毕，但没有通过上升沿更新数值
	// return;
}


// 根据历史结果输出相对值

// 设置对应的位为高电平
void s2p_set(unsigned char bit_mask)
{
	s2p_write_data(last_data | bit_mask);
}

// 设置对应的位为低电平
void s2p_clr(unsigned char bit_mask)
{
	s2p_write_data(last_data & ~bit_mask);
}

// 设置所有位 (全置高电平)
void s2p_set_all()
{
	s2p_write_data(0xff);
}

// 清除所有位 (全置低电平)
void s2p_clr_all()
{
	s2p_write_data(0);
}

// 获取最后一次输出结果
unsigned char s2p_get_last_data()
{
	return last_data;
}

// 历史值循环左移 1 位
void s2p_crol_1()
{
	// 向 74HC595 的寄存器的最低位推一个对应的电平
	S2P_SHIFT_BIT(last_data >> 7);
	last_data = _crol_(last_data, 1);
	// 在移位寄存器时钟线上建立一个上升沿
	S2P_SREDGE();
	// 在锁存寄存器时钟线上建立一个上升沿
	S2P_REDGE();
}

// 历史值左移 1 位
void s2p_rol_1()
{
	// 向 74HC595 的寄存器的最低位推一个低电平
	S2P_SHIFT_BIT(0);
	last_data <<= 1;
	// 在移位寄存器时钟线上建立一个上升沿
	S2P_SREDGE();
	// 在锁存寄存器时钟线上建立一个上升沿
	S2P_REDGE();
}

// 历史值循环左移 n 位
void s2p_crol(int n)
{
	s2p_write_data(_crol_(last_data, n));	// _crol_ 进行 8 位二进制的循环左移
}

// 历史值循环右移 n 位
void s2p_cror(int n)
{
	s2p_write_data(_cror_(last_data, n));	// _cror_ 进行 8 位二进制的循环右移
}

// 历史值左移 n 位
void s2p_rol(int n)
{
	s2p_write_data(last_data << n);
}

// 历史值右移 n 位
void s2p_ror(int n)
{
	s2p_write_data(last_data >> n);
}
